//////////////////////////////////////////////////////////////
// Basic mesh class for DX11
// mesh contains a single vertex buffer and index buffer
// the m_subsets is grouped according to material information
// all the triangles with the same material are grouped into one subsets
// This mesh can be created using objImpoart class.

#pragma once
//#include "util.h"
#include "obj_loader.h"

//////////////////////////////////////////////////////////////////////////////////////////////////////////
// To Render dx11 mesh object:

/*********************************************************************************************
	UINT strides = sizeof( StandardVertex );
	UINT offsets = 0;
	pd3dContext->IASetInputLayout( m_pLayoutScene );
	pd3dContext->IASetVertexBuffers( 0, 1, &m_MeshHead.m_pVertexBuffer, &strides, &offsets );
	pd3dContext->IASetIndexBuffer( m_MeshHead.m_pIndexBuffer, DXGI_FORMAT_R32_UINT, 0 );
	pd3dContext->IASetPrimitiveTopology( D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST );

	ID3D11ShaderResourceView*	pSRV[8] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL };

	// set shader
	pd3dContext->VSSetShader( m_pVSRenderScene, NULL, 0 );
	pd3dContext->PSSetShader( m_pPSSceneShading, NULL, 0 );

	for(int i=0; i<m_MeshHead.m_Subsets.size(); i++)
	{
		// Set material value for each subset
		hr = pd3dContext->Map( m_pcbPerMaterial, 0, D3D11_MAP_WRITE_DISCARD, 0, &MappedResource ) ;
		if (FAILED(hr))
			::MessageBoxA(0, "Fail to map constant buffer material", "d3d error", 0);

		CB_PER_MATERIAL* pcbPerMaterial = ( CB_PER_MATERIAL* )MappedResource.pData;

		const Material* pMat = &m_MeshHead.m_Materials[m_MeshHead.m_Subsets[i].materialID];
		pcbPerMaterial->m_MatAmbient = D3DXVECTOR4(pMat->vAmbient, 1);
		pcbPerMaterial->m_MatDiffuse = D3DXVECTOR4(pMat->vDiffuse, -1);
		pcbPerMaterial->m_MatSpecular = D3DXVECTOR4(pMat->vSpecular, pMat->nShininess);
		
		// Set shader resource view
		if(	pMat->pTextureRV11)
		{
			pcbPerMaterial->m_MatDiffuse.w = 1;
			pSRV[6] = pMat->pTextureRV11;
			pd3dContext->PSSetShaderResources(0, 8, pSRV);
		}

		pd3dContext->Unmap( m_pcbPerMaterial, 0 );

		pd3dContext->VSSetConstantBuffers( 1, 1, &m_pcbPerMaterial );
		pd3dContext->PSSetConstantBuffers( 1, 1, &m_pcbPerMaterial );

		int indexCount = m_MeshHead.m_Subsets[i].triangleCount*3;
		int startLocation = m_MeshHead.m_Subsets[i].startIndex;
		pd3dContext->DrawIndexed( indexCount, startLocation, 0 );
	}

********************************************************************************/

//// the vertex layout for the mesh structure
//static const D3D11_INPUT_ELEMENT_DESC layout_mesh[] =
//{
//    { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0,  0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
//    { "NORMAL",   0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 },
//    { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT,    0, 24, D3D11_INPUT_PER_VERTEX_DATA, 0 },
//};

class CDX11Mesh
{
public:
	// Vertex format
	struct Vertex
	{
		D3DXVECTOR3 pos;    // position
		D3DXVECTOR3 norm;   //normal
		D3DXVECTOR2 tex;    //texture coordinate
	};

	// Used for a hashtable vertex cache when creating the mesh from a .obj file
	struct CacheEntry
	{
		UINT index;
		CacheEntry* pNext;
	};

    struct Material
    {
        D3DXVECTOR3 vAmbient;
        D3DXVECTOR3 vDiffuse;
        D3DXVECTOR3 vSpecular;

        int nShininess;
        float fAlpha;

        bool bSpecular;

        WCHAR   strTexture[FILENAME_MAX];
        ID3D11ShaderResourceView* pTextureRV11; // for d3d 11
        Material()
        {
            vAmbient = D3DXVECTOR3( 172/255.0f, 120/255.0f, 83/255.0f )*0.1;
            vDiffuse = D3DXVECTOR3( 172/255.0f, 120/255.0f, 83/255.0f )*0.3;
            vSpecular = D3DXVECTOR3( 0.02f, 0.02f, 0.02f );

            nShininess = 1;
            fAlpha = 1.0;

            bSpecular = false;
            strTexture[0] = 0;
            pTextureRV11 = 0;
        }
    };

    struct Subset
    {
        int startIndex;
        int triangleCount;
        int materialID;
    };

public:
	CDX11Mesh(void);
	~CDX11Mesh(void);
	void CreateMeshFromOBJFile(ID3D11Device* pd3dDevice, const WCHAR* strFilename, 
								D3DXVECTOR3 scale = D3DXVECTOR3(1,1,1), 
								D3DXVECTOR3 rotation = D3DXVECTOR3(0, 0, 0), 
								D3DXVECTOR3 translation = D3DXVECTOR3(0, 0, 0));

	void CreateMeshFromOBJMemory(ID3D11Device* pd3dDevice, COBJLoader& objImport, 
								D3DXVECTOR3 scale = D3DXVECTOR3(1,1,1), 
								D3DXVECTOR3 rotation = D3DXVECTOR3(0, 0, 0), 
								D3DXVECTOR3 translation = D3DXVECTOR3(0, 0, 0));

	void OnDestroy();
	
    ID3D11Buffer* GetVertexBuffer() { return m_pVertexBuffer; }
    ID3D11Buffer* GetIndexBuffer() { return m_pIndexBuffer; }
    
    std::vector<Subset> const& GetSubsets() const { return m_Subsets; }			// all the sub meshes, each with different material property
    std::vector<Material> const& GetMaterials() const { return	m_Materials; }

    D3DXVECTOR3 GetBBMax() const                        { return m_bbMax; }
    D3DXVECTOR3 GetBBMin() const                        { return m_bbMin; }

private:
	std::vector<Subset>		m_Subsets;			// all the sub meshes, each with different material property
	std::vector<Material>	m_Materials;
	ID3D11Buffer*			m_pVertexBuffer;
	ID3D11Buffer*			m_pIndexBuffer;

    D3DXVECTOR3             m_bbMax;
    D3DXVECTOR3             m_bbMin;
};